package com.virtualparadigm.compositor;

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;

import com.virtualparadigm.identity.Identifiable;

public class ManyToOneAggregate<ThisType extends Identifiable, ThatType extends Identifiable> implements Serializable
{
	private static final long serialVersionUID = 1L;
	
	private ThisType instance;
	private OneToManyAggregate<ThatType, ThisType> oneToManyAggregate;
	
	public ManyToOneAggregate(ThisType instance, OneToManyAggregate<ThatType, ThisType> aggregate)
	{
		this.setInstance(instance);
		this.setOneToManyAggregate(aggregate);
	}
	
	public ThisType getInstance()
	{
		return instance;
	}
	private void setInstance(ThisType instance)
	{
		this.instance = instance;
	}

	// get aggregate
	// package protected
	OneToManyAggregate<ThatType, ThisType> getOneToManyAggregate()
	{
		return this.oneToManyAggregate;
	}
	
	public ThatType getAggregate()
	{
		ThatType typedAggregate = null;
		OneToManyAggregate<ThatType, ThisType> oneToManyAggregate = this.getOneToManyAggregate();
		if(oneToManyAggregate != null)
		{
			typedAggregate = oneToManyAggregate.getInstance();
		}
		return typedAggregate;
	}
	
	// package protected
	boolean setOneToManyAggregate(OneToManyAggregate<ThatType, ThisType> oneToManyAggregate)
	{
		if(this.oneToManyAggregate == null)
		{
			if(oneToManyAggregate != null)
			{
				this.oneToManyAggregate = oneToManyAggregate;
				oneToManyAggregate.addManyToOneAggregate(this);
			}
		}
		else
		{
			if(!this.oneToManyAggregate.equals(oneToManyAggregate))
			{
				OneToManyAggregate<ThatType, ThisType> tempAggregate = this.oneToManyAggregate;
				this.oneToManyAggregate = oneToManyAggregate;
				tempAggregate.removeAggregate(this.getInstance().getResourceIdentifier());
				if(oneToManyAggregate == null)
				{
//					this.handleRemovedAggregate();
					// dont need to do anything to children with aggregation
				}
				else
				{
					oneToManyAggregate.addManyToOneAggregate(this);
				}
			}
		}
		return true;
	}
	
	public boolean setAggregate(ThatType that)
	{
		OneToManyAggregate<ThatType, ThisType> oneToManyAggregate = null;
		if(that != null)
		{
			oneToManyAggregate = new OneToManyAggregate<ThatType, ThisType>(that);
		}
		return this.setOneToManyAggregate(oneToManyAggregate);
	}

	// if this composite part has other composite parts as children, they should be cleaned up as 
	// well in the implementation of this method
//	abstract boolean handleRemovedAggregate();
	

	// ================================================
	// UTILITY METHODS
	// ================================================
	public String toString()
	{
//		return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
		return ReflectionToStringBuilder.toString(this, ToStringStyleBuilder.toStringStyle);
	}
	public int hashCode()
	{
		HashCodeBuilder builder = new HashCodeBuilder();
	    builder.append(this.getInstance().getResourceIdentifier());
	    return builder.toHashCode();		
	}
	public boolean equals(Object obj)
	{
		if (obj == null)
		{
			return false;
		}
		if (obj == this)
		{
			return true;
		}
		if (obj.getClass() != getClass())
		{
			return false;
		}
		ManyToOneAggregate<ThisType, ThatType> that = (ManyToOneAggregate<ThisType, ThatType>)obj;
		EqualsBuilder builder = new EqualsBuilder();
	    builder.append(this.getInstance().getResourceIdentifier(), that.getInstance().getResourceIdentifier());
		return builder.isEquals();
	}

	
}